package com.sxsihe.heartmate;

import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.*;
import android.text.format.Time;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.*;
import android.widget.*;

import com.neurosky.connection.ConnectionStates;
import com.neurosky.connection.DataType.BodyDataType;
import com.neurosky.connection.TgStreamHandler;
import com.neurosky.connection.TgStreamReader;
import com.neurosky.ecg.TGLibECG;
import com.neurosky.ecg.TGLibECGCallback;
import com.sxsihe.heartmate.util.FileStates;
import com.sxsihe.heartmate.util.SharePreferenceUtil;
import com.sxsihe.heartmate.view.DrawWaveView;
import com.sxsihe.heartmate.view.TimePopupWindow;
import org.w3c.dom.Text;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class RealTimeActivity extends Activity implements View.OnClickListener {

    private static final int MSG_UPDATE_PRESSING_STATE = 1000;
    private static final int MSG_UPDATE_BAD_PACKET = 1001;
    private static final int MSG_UPDATE_STATE = 1002;
    private static final int MSG_UPDATE_SINGNAL_QUALITY = 1003;
    private static final int MSG_UPDATE_OVERALL_SINGNAL_QUALITY = 1004;


    private static final String TAG = RealTimeActivity.class.getSimpleName();

    private TgStreamReader mTgStreamReader;
    private BluetoothAdapter mBluetoothAdapter;
    private TGLibECG mLibECG;
    private DrawWaveView mWaveView = null;
    private Button signal_btn, linked_btn;


    /*暂且不用的变量*/
    private int mBadPacketCount = 0;

    boolean mIisWorking = false;
    volatile int mPoorSignal = 0;
    boolean mIsPress = false;
    boolean mIsFirstRaw = false;
    boolean mIsStopped = false;
    boolean mIsSaving = false;
    boolean isDraw = false;
    private int averHeartRate = 0;
    boolean beginVibrator, is_alarm = false;

    TextView mTvTime;
    TextView mTvHeartRate, result_btn, hrvvalue, mood, r2r;
    int heartCount, _r2r, _mood, _stress, _heart_age;
    long time_start, time_end;
    Button mBtnSave, save_btn, draw_btn;
    ImageView back_icon;
    CheckBox save;
    private SoundPool soundPool;
    int rateMin, rateMax;
    SharePreferenceUtil spu;
    private Vibrator vibrator;
    int duration;
    LinearLayout root_layout;


    Drawable signalDrawable1, signalDrawable2, linkDrawable1, linkDrawable2;

    ImageView mIvHeartRate;
    FileOutputStream mFileWriter;

    Timer mTimer = new Timer();
    TimerTask mTask = new TimerTask() {
        @Override
        public void run() {
            // 需要做的事:发送消息
            Message message = new Message();
            message.what = 1;
            mTimerHandler.sendMessage(message);
        }
    };

    Handler mTimerHandler = new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                Time t = new Time();
                t.setToNow();
                mTvTime.setText(t.hour + ":" + t.minute + ":" + t.second);
            }
            super.handleMessage(msg);
        }
    };

    private Handler uiHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    linked_btn.setText("未连接");
                    linked_btn.setCompoundDrawables(null, linkDrawable1, null, null);
                    signal_btn.setCompoundDrawables(null, signalDrawable1, null, null);
                    signal_btn.setText("信号0%");
                    break;
            }
        }
    };

    private Handler mLinkDetectedHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BodyDataType.CODE_RAW:
                    //信号为0时也要画线
//                    if (mPoorSignal == 0) {
//                        return;
//                    }
                    mLibECG.requestECGAnalysis(msg.arg1, mPoorSignal);
                    if(fos != null){
                        String buf = msg.arg1 + "\n";
                        try {
                            fos.write(buf.getBytes());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case BodyDataType.CODE_POOR_SIGNAL:
                    mPoorSignal = msg.arg1;
                    if (mPoorSignal != 0) {
                        signal_btn.setCompoundDrawables(null, signalDrawable2, null, null);
                    } else {
                        signal_btn.setCompoundDrawables(null, signalDrawable1, null, null);
                    }
                    signal_btn.setText("信号" + mPoorSignal / 2 + "%");
                    if (mIsFirstRaw) {
                        mIsFirstRaw = false;
                        mIsStopped = false;
                        mLinkDetectedHandler.sendEmptyMessageDelayed(MSG_UPDATE_SINGNAL_QUALITY, 4000);
                    }
                    if (mIsPress) {
                        if (mPoorSignal == 0) { // stop when release fingers
                            mIsPress = false;
                            mTgStreamReader.connectAndStart();
                            mLinkDetectedHandler.sendEmptyMessage(MSG_UPDATE_OVERALL_SINGNAL_QUALITY);
                        }
                    } else {
                        if (mPoorSignal > 0) {
                            mIsPress = true;
                        }
                    }
                    break;
                case MSG_UPDATE_BAD_PACKET:
                    break;
                case MSG_UPDATE_STATE:
                    if (msg.arg1 == ConnectionStates.STATE_STOPPED) {
                        linked_btn.setText("未连接");
                        linked_btn.setCompoundDrawables(null, linkDrawable1, null, null);
                    }
                    if (msg.arg1 == ConnectionStates.STATE_CONNECTED) {
                        linked_btn.setText("已连接");
                        linked_btn.setCompoundDrawables(null, linkDrawable2, null, null);
                    }
                    if (msg.arg1 == ConnectionStates.STATE_DISCONNECTED) {
                        linked_btn.setText("未连接");
                        linked_btn.setCompoundDrawables(null, linkDrawable1, null, null);
                    }
                    break;
                case MSG_UPDATE_OVERALL_SINGNAL_QUALITY:
                    break;

                case MSG_UPDATE_SINGNAL_QUALITY:
                    if (!mIsStopped) {
                        mLinkDetectedHandler.sendEmptyMessageDelayed(MSG_UPDATE_SINGNAL_QUALITY, 4000);
                    }
                    break;

                default:
                    break;
            }
            super.handleMessage(msg);
        }
    };

    private TgStreamHandler mDataCallback = new TgStreamHandler() {
        @Override
        public void onStatesChanged(int connectionStates) {
            switch (connectionStates) {
                case ConnectionStates.STATE_CONNECTED:
                    mPoorSignal = 0;
                    break;
                case ConnectionStates.STATE_WORKING:
                    mIsFirstRaw = true;
                    mIisWorking = true;
                    break;
                case ConnectionStates.STATE_GET_DATA_TIME_OUT:
                    // can't get data
                    if (mIisWorking) {
                        mIsStopped = true;
                        mIisWorking = false;
                        mLinkDetectedHandler.sendEmptyMessage(MSG_UPDATE_OVERALL_SINGNAL_QUALITY);
                    }
                    uiHandler.sendEmptyMessage(0);
                    break;
                case ConnectionStates.STATE_STOPPED:
                    if (mIisWorking) {
                        mIsStopped = true;
                        mIisWorking = false;
                    }
                    break;
                case ConnectionStates.STATE_DISCONNECTED:
                    break;
                case ConnectionStates.STATE_ERROR:

                    break;
                case ConnectionStates.STATE_FAILED:
                    break;
            }
            Message msg = mLinkDetectedHandler.obtainMessage();
            msg.what = MSG_UPDATE_STATE;
            msg.arg1 = connectionStates;
            mLinkDetectedHandler.sendMessage(msg);
        }

        @Override
        public void onRecordFail(int a) {
            Log.e(TAG, "onRecordFail: " + a);
        }

        @Override
        public void onChecksumFail(byte[] payload, int length, int checksum) {

            mBadPacketCount++;
            Message msg = mLinkDetectedHandler.obtainMessage();
            msg.what = MSG_UPDATE_BAD_PACKET;
            msg.arg1 = mBadPacketCount;
            mLinkDetectedHandler.sendMessage(msg);
        }

        @Override
        public void onDataReceived(int datatype, int data, Object obj) {
            Message msg = mLinkDetectedHandler.obtainMessage();
            msg.what = datatype;
            msg.arg1 = data;
            msg.obj = obj;
            mLinkDetectedHandler.sendMessage(msg);
        }
    };

    public static String TIME_FORMAT = "HH:mm:ss";

    public static String convert2String(long time, String format) {
        SimpleDateFormat sf = new SimpleDateFormat(format);
        Date date = new Date(time);
        return sf.format(date);

    }

    private SoundPool pool;

    int soundId;

    public int initSound() {
        if (Build.VERSION.SDK_INT > 21) {
            SoundPool.Builder builder = new SoundPool.Builder();
            builder.setMaxStreams(2);
            AudioAttributes.Builder builder1 = new AudioAttributes.Builder();
            builder1.setLegacyStreamType(AudioManager.STREAM_MUSIC);
            builder.setAudioAttributes(builder1.build());
            pool = builder.build();

        } else {
            //21版本以前使用SoundPool(int maxStreams, int streamType, int srcQuality)
            pool = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
        }
        return pool.load(getApplicationContext(), R.raw.beep, 1);

    }
    String address;

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.realtime);
        address = this.getIntent().getExtras().getString("address");
        System.out.println("address:" + address);
        vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
        soundId = initSound();
        if (spu == null) {
            spu = SharePreferenceUtil.getInstance(this);
        }
        rateMin = Integer.parseInt(spu.get("rateMin", "60"));
        rateMax = Integer.parseInt(spu.get("rateMax", "100"));
        is_alarm = Boolean.valueOf(spu.get("is_alarm", "true"));
        TgStreamReader.redirectConsoleLogToDocumentFolder();
        try {
            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
                Toast.makeText(this, "请打开蓝牙!", Toast.LENGTH_LONG).show();
                finish();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        signalDrawable1 = getResources().getDrawable(R.drawable.signal1);
        signalDrawable1.setBounds(0, 0, signalDrawable1.getMinimumWidth(), signalDrawable1.getMinimumHeight());
        signalDrawable2 = getResources().getDrawable(R.drawable.signal2);
        signalDrawable2.setBounds(0, 0, signalDrawable2.getMinimumWidth(), signalDrawable2.getMinimumHeight());

        linkDrawable1 = getResources().getDrawable(R.drawable.link1);
        linkDrawable1.setBounds(0, 0, linkDrawable1.getMinimumWidth(), linkDrawable1.getMinimumHeight());
        linkDrawable2 = getResources().getDrawable(R.drawable.link2);
        linkDrawable2.setBounds(0, 0, linkDrawable2.getMinimumWidth(), linkDrawable2.getMinimumHeight());


        mLibECG = new TGLibECG(ecgCallback);
        mLibECG.enableLogCatMessages(true);

        root_layout = (LinearLayout) findViewById(R.id.root_layout);
        mWaveView = (DrawWaveView) findViewById(R.id.curveView);
        mTvHeartRate = (TextView) findViewById(R.id.heartratevalue);
//        hrvvalue = (TextView) findViewById(R.id.hrvvalue);
        save = (CheckBox) findViewById(R.id.save);
        mWaveView.setValue(1550, 8000, -8000);
        mWaveView.updateDensity();


        signal_btn = (Button) findViewById(R.id.signal_btn);
        linked_btn = (Button) findViewById(R.id.linked_btn);

        back_icon = (ImageView) findViewById(R.id.back_icon);
        back_icon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                isDraw = false;
                save.setChecked(false);
                RealTimeActivity.this.finish();
            }
        });

        draw_btn = (Button) findViewById(R.id.draw_btn);
        draw_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isDraw) {
                    draw_btn.setText("开始绘制");
                    time_end = System.currentTimeMillis();
                } else {
                    draw_btn.setText("停止绘制");
                    time_start = System.currentTimeMillis();
//                    if(duration!=0){
//                        draw_btn.performClick();
//                        save.performClick();
//                        uiHandler.postDelayed(autoRun, duration);
//                    }
                }
                isDraw = !isDraw;
//                if (isDraw) {
//                    draw_btn.setText("开始绘制");
//                    time_end = System.currentTimeMillis();
//                    isDraw = !isDraw;
//                    if(mIsSaving){
//                        save.setChecked(false);
//
//                    }
//                    try{
//                        uiHandler.removeCallbacks(autoRun);
//                    }catch (Exception e){
//
//                    }
//
//                } else {
//                    showTimeWindow();
//                }
            }
        });

        save.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                try {
                    if (isChecked) {
                        showTimeWindow();
                    } else {
                        mTgStreamReader.stopRecordRawData();
                        try {
                            uiHandler.removeCallbacks(autoRun);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        time_end = System.currentTimeMillis();
                        System.out.println("time_end:" + time_end);
                        mIsSaving = false;
                        int status = 0;
                        if (averHeartRate >= 60 && averHeartRate <= 90) {
                            status = 1;
                        }
                        String tmp = "averHeartRate:" + averHeartRate;
                        tmp += "|heart_age:" + _heart_age +
                                "|heart_count:" + heartCount +
                                "|r2r:" + _r2r +
                                "|mood:" + _mood +
                                "|stress:" + _stress +
                                "|signal:" + mPoorSignal +
                                "|status:" + status +
                                "|duration:" + (int) (time_end - time_start) / 1000;
                        mFileWriter.write(tmp.getBytes());
                        mFileWriter.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        result_btn = (TextView) findViewById(R.id.result_btn);
        result_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (time_start != 0)
                    time_end = System.currentTimeMillis();
                if (save.isChecked()) {
                    save.performClick();
                }
                if (isDraw) {
                    draw_btn.performClick();
                }
                final int _heartrate = averHeartRate >= 160 ? 160 : averHeartRate;
                Intent intent = new Intent(RealTimeActivity.this, DiagnoseActiviy2.class);
                intent.putExtra("heart_age", _heart_age + "");
                intent.putExtra("heart_count", heartCount + "");
                intent.putExtra("r2r", _r2r + "");
                intent.putExtra("mood", _mood + "");
                intent.putExtra("stress", _stress + "");
                intent.putExtra("heartrate", _heartrate + "");
                intent.putExtra("signal", mPoorSignal / 2 + "%");
                intent.putExtra("duration", (int) (time_end - time_start) / 1000 + "");
                intent.putExtra("type", "bluetooth");

                startActivity(intent);
                finish();
            }
        });
    }


    TimePopupWindow popWindow;

    public void showTimeWindow() {
        if (popWindow != null && popWindow.isShowing()) {
            return;
        }
        popWindow = new TimePopupWindow(this, this);
        popWindow.showAtLocation(root_layout, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
    }


    Runnable autoRun = new Runnable() {
        @Override
        public void run() {
            save.performClick();
        }
    };

    protected void onPause() {
        super.onPause();
        if (mIsSaving) {
            save.performClick();
        }
        if (isDraw) {
            draw_btn.performClick();
        }
    }

    protected void onResume() {
        super.onResume();
        start();
        draw_btn.setText("开始绘制");
    }

    @Override
    protected void onStop() {
        super.onStop();
        uiHandler.removeCallbacks(autoRun);
        pool.release();
        vibrator.cancel();
        stop();
        draw_btn.setText("停止绘制");
        isDraw = false;
    }

    private void resetECG() {
        int outputInterval = 30;
        int heartAgeRecordNumber = 1;
        int threshold = 3;
        String user_name = "User";
        int weight = 65;
        int height = 170;
        int age = 30;
        boolean female = true;
        String path = "";

        mLibECG.resetECGAnalysis();
        mLibECG.setSignalQualityThreshold(threshold);
        mLibECG.setHRVOutputInterval(outputInterval);
        mLibECG.setMoodOutputPoint(outputInterval);
        mLibECG.setHeartAgeOutputPoint(outputInterval);
        mLibECG.setHeartAgeParameters(user_name, age, path);
        mLibECG.setHeartAgeRecordNumber(heartAgeRecordNumber);
        mLibECG.setStressOutputInterval(outputInterval);
        mLibECG.setStressParameters(user_name, female, age, height, weight, path);
    }

    public void start() {
        resetECG();
        mTgStreamReader = new TgStreamReader(mBluetoothAdapter, mDataCallback);
        mTgStreamReader.connectAndStart();
        mTgStreamReader.setGetDataTimeOutTime(6);//5s for default
//        mTgStreamReader.startLog();
//        mTgStreamReader.startRecordRawData();

//        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
//        Method m = null;
//       try{
//           m = device.getClass().getMethod("createRfcommSocket",
//                   new Class[] { int.class });
//           BluetoothSocket socket = (BluetoothSocket) m.invoke(device, 1);
//           socket.connect();
//
//       }catch (Exception e){
//           e.printStackTrace();
//       }
    }

    private  FileOutputStream fos = null;

//    public void startRecordRawData(){
//        if(!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
//            Log.e(TAG,"SD do not mounted:" + Environment.getExternalStorageState() );
//            return ;
//        }
//        String path = Environment.getExternalStorageDirectory() +"/neurosky/heartmate/RawData/";
//        File dir = new File(path);
//        if(!dir.exists()) dir.mkdirs();
//        SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyyMMdd_HH_mm_ss");
//        String fileName =  dateFormatGmt.format(new Date())+".txt";
//
//        File outputFile = new File(dir, fileName);
//        fos = null;
//        try {
//            fos =   new FileOutputStream(outputFile);
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
//    }
//
//    public void stopRecordRawData(){
//        if(fos == null){
//            return;
//        }
//        try {
//            fos.flush();
//            fos.close();
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }finally{
//            fos = null;
//        }
//    }


    public void stop() {
        if (mTgStreamReader != null) {
            mTgStreamReader.stop();
            mTgStreamReader.close();
            mTgStreamReader = null;
        }
    }

    public void startRecord(int raw) {
        if (mIsSaving) {
            long mills = Calendar.getInstance().getTimeInMillis();
            String line = mills + "|" + raw / 15 * 10 + "|" + (averHeartRate == 0 ? " " : averHeartRate) + "\r\n";
            try {
                mFileWriter.write(line.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void updateWaveView(int data) {
        if (mWaveView != null) {
            int d = data / 12 * 10;
            mWaveView.updateData(d);
            startRecord(d);
        }
    }

    public void updateWaveView(String str, int data) {
        if (mWaveView != null) {
            int d = data / 12 * 10;
            if (mPoorSignal == 0) {
                d = 0;
            }
            mWaveView.updateData(str, d);
            startRecord(d);
        }
    }

    public TGLibECGCallback ecgCallback = new TGLibECGCallback() {
        @Override
        public void dataReceived(int key, Object data) {
            runOnUiThread(new EcgData(key, data));
        }
    };

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_1min:
                duration = 60000;
                break;
            case R.id.btn_3min:
                duration = 180000;
                break;
            case R.id.btn_no_limit:
                duration = 0;
                break;
        }
        try {
            popWindow.dismiss();
            time_start = System.currentTimeMillis();
            long timestamp =  new Date().getTime();
            String file = timestamp+ ".data";
            mTgStreamReader.setRecordStreamFilePath("/sdcard/neurosky/"+timestamp);
            mTgStreamReader.startRecordRawData();
            mIsSaving = true;
            FileStates.changed = true;
            mFileWriter = openFileOutput(file, Context.MODE_PRIVATE);
            if (duration != 0) {
                uiHandler.postDelayed(autoRun, duration);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
//        if (isDraw) {
//            draw_btn.setText("开始绘制");
//            time_end = System.currentTimeMillis();
//        } else {
//            draw_btn.setText("停止绘制");
//            time_start = System.currentTimeMillis();
//            if(duration!=0){
////              draw_btn.performClick();
//                save.performClick();
//                uiHandler.postDelayed(autoRun, duration);
//            }
//        }
//        isDraw = !isDraw;
    }

    public class EcgData implements Runnable {
        int key;
        Object data;

        public EcgData(int k, Object d) {
            key = k;
            data = d;
        }

        @Override
        public void run() {
            if (isDraw) {
                switch (key) {
                    case TGLibECG.MSG_ECG_SMOOTHED_WAVE:
                        updateWaveView(convert2String(new Date().getTime(), TIME_FORMAT), (Integer) data);
                        break;
                    case TGLibECG.MSG_ECG_HEART_RATE:
                        heartCount++;
                        averHeartRate = Integer.parseInt(data.toString());
                        if (averHeartRate < rateMin || averHeartRate > rateMax) {
                            mTvHeartRate.setTextColor(Color.RED);
                        } else {
                            mTvHeartRate.setTextColor(Color.parseColor("#9A9A9A"));
                        }
                        mTvHeartRate.setText(data.toString());
                        beginVibrator = true;
                        break;

                    case TGLibECG.MSG_ECG_R2R_INTERVAL:
                        _r2r = Integer.parseInt(data.toString());
                        break;
                    case TGLibECG.MSG_ECG_HRV:
                        //                        hrvvalue.setText(data.toString());
                        break;
                    case TGLibECG.MSG_ECG_RPEAK_DETECTED:
                        break;
                    case TGLibECG.MSG_ECG_MOOD:
                        _mood = Integer.parseInt(data.toString());

                        break;
                    case TGLibECG.MSG_ECG_STRESS:
                        _stress = Integer.parseInt(data.toString());

                        break;
                    case TGLibECG.MSG_ECG_HEART_AGE:
                        _heart_age = Integer.parseInt(data.toString());

                        break;
                    case TGLibECG.MSG_ECG_HEART_RATE_ROBUST:
                        pool.play(soundId, 1, 1, 100, 0, 1);
                        if (beginVibrator && is_alarm) {
                            if (averHeartRate < rateMin || averHeartRate > rateMax) {
                                vibrator.vibrate(30);
                            }
                        }
                        break;
                    case TGLibECG.MSG_ECG_EXCEPTION:
                        break;
                }
            }
        }
    }
}
